import { glob } from "glob";
import { writeFile } from "node:fs/promises";
import { resolve } from "node:path";
import { format } from "prettier";
import { Node, Project } from "ts-morph";

import { alphaNumericSort } from "../src/utils/alphaNumericSort.js";
import { PRIVATE_FILES } from "./constants.js";

const files = await glob("src/**/*.{ts,tsx}", {
  cwd: process.cwd(),
  ignore: ["**/__tests__/**", "**/test-utils/**", ...PRIVATE_FILES],
});
const project = new Project({
  tsConfigFilePath: "./tsconfig.types.json",
  skipLoadingLibFiles: true,
  skipAddingFilesFromTsConfig: true,
});

const types = new Set<string>();
const variables = new Set<string>();
const exportMap: Record<string, string> = {};
files.forEach((file) => {
  const exportPath = file
    .replace("src", "@react-md/core")
    .replace(/\.tsx?$/, "");

  project.addSourceFileAtPath(file);
  const sourceFile = project.getSourceFileOrThrow(file);
  const exportDeclarations = sourceFile.getExportedDeclarations();

  for (const [name, declarations] of exportDeclarations) {
    if (
      declarations.find(
        (decl) =>
          Node.isTypeAliasDeclaration(decl) || Node.isInterfaceDeclaration(decl)
      )
    ) {
      types.add(name);
    } else {
      variables.add(name);
    }

    exportMap[name] = exportPath;
  }
});

const sortedExports = Object.fromEntries(
  alphaNumericSort(Object.entries(exportMap), {
    extractor: ([name]) => name,
  })
);
const sortedTypes = alphaNumericSort([...types]);
const sortedVariables = alphaNumericSort([...variables]);

await writeFile(
  resolve("../codemod/src/transforms/v5-to-v6/coreExportMap.ts"),
  await format(
    `// THIS FILE WAS GENERATED BY A SCRIPT AND SHOULD NOT BE UPDATED MANUALLY

export const TYPES: ReadonlySet<string> = new Set(${JSON.stringify(sortedTypes)});
export const VARIABLES: ReadonlySet<string> = new Set(${JSON.stringify(sortedVariables)});
export const EXPORT_MAP: Record<string, string> = ${JSON.stringify(sortedExports, null, 2)};

`,
    { parser: "typescript" }
  ),
  "utf8"
);
